#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
Created on 2018年1月16日

@author: heguofeng
'''
import unittest
from PIL import Image,ImageDraw
from _stat import S_ISDIR, S_ISREG
import os
from functools import reduce

def make_regalur_image(img, size = (256, 256)):
    return img.resize(size).convert('RGB')

def split_image(img, part_size = (64, 64)):
    w, h = img.size
    pw, ph = part_size
    
    assert w % pw == h % ph == 0
    
    return [img.crop((i, j, i+pw, j+ph)).copy() \
                for i in range(0, w, pw) \
                for j in range(0, h, ph)]

def hist_similar(lh, rh):
    assert len(lh) == len(rh)
    return sum(1 - (0 if l == r else float(abs(l - r))/max(l, r)) for l, r in zip(lh, rh))/len(lh)

def calc_similar(li, ri):
#    return hist_similar(li.histogram(), ri.histogram())
    return sum(hist_similar(l.histogram(), r.histogram()) for l, r in zip(split_image(li), split_image(ri))) / 16.0
            

def calc_similar_by_path(lf, rf):
    li, ri = make_regalur_image(Image.open(lf)), make_regalur_image(Image.open(rf))
    return calc_similar(li, ri)

def make_doc_data(lf, rf):
    li, ri = make_regalur_image(Image.open(lf)), make_regalur_image(Image.open(rf))
    li.save(lf + '_regalur.png')
    ri.save(rf + '_regalur.png')
    fd = open('stat.csv', 'w')
    fd.write('\n'.join(l + ',' + r for l, r in zip(map(str, li.histogram()), map(str, ri.histogram()))))
#    print >>fd, '\n'
#    fd.write(','.join(map(str, ri.histogram())))
    fd.close()
    

    li = li.convert('RGB')
    draw = ImageDraw.Draw(li)
    for i in range(0, 256, 64):
        draw.line((0, i, 256, i), fill = '#ff0000')
        draw.line((i, 0, i, 256), fill = '#ff0000')
    li.save(lf + '_lines.png')

def avhash(img):
    if not isinstance(img, Image.Image):
        img = Image.open(img)
    img = img.resize((8, 8), Image.ANTIALIAS).convert('L') #将image压缩为8*8,转化为灰度图
    avg = reduce(lambda x, y: x + y, img.getdata()) / 64. #对每个像素点的灰度累和,最后除以64,得到灰度的平均值

    #这一句代码很pythonic,需要仔细消化
    #map对每个像素做判断,大于平均值为1,否则为0
    #enumerate函数返回一个列表的下标及该下标对应的元素,用tuple装起来: (index, element)
    #reduce,对每个元素右移对应的下标位,并且与前一个元素做或运算,最终得到的结果为一个
    # 64位的二进制数,每一位的0,1代表该位的像素灰度与平均像素灰度的比较结果
    return reduce(lambda x, y: x | (y[1] << y[0]), enumerate(map(lambda i: 0 if i < avg else 1, img.getdata())), 0)

#计算汉明距离
def hamming(h1, h2):
    #直接对两个数按位做异或操作,这样得到一个64位的二进制数,该二进制数包含的1的个数,即为汉明距离
    h, d = 0, h1 ^ h2
    #求d中包含的1的个数
    while d:
        h += 1
        d &= d - 1
    return h

def calc_similar_by_path2(lf, rf):
    h1 = avhash(lf)
    h2 = avhash(rf)
    return 1-hamming(h1, h2)/64

if __name__ == '__main__':
    path = r'C:/Users/heguofeng/Downloads/test/TEST%d/%d.JPG'
    for i in range(1, 8):
        h1 = avhash(path %(i, 1))
        h2 = avhash(path %(i, 2))
        
        print('new test_case_%d: %.3f%%'%(i, (1-hamming(h1, h2)/64)*100))
        
    for i in range(1, 8):
        print('test_case_%d: %.3f%%'%(i, \
            calc_similar_by_path(path %(i, 1), path %(i, 2))*100))
    full_path= "D:/My Pictures/200508敦煌照片"
    files = os.listdir(full_path)
    maxsimilar=  0
    for i in range(0,len(files)):
        f1_full_path = os.path.join(full_path, files[i])
        for j in range(i+1,len(files)):
            f2_full_path = os.path.join(full_path,files[j])

            if S_ISREG(os.stat(f1_full_path).st_mode) and S_ISREG(os.stat(f2_full_path).st_mode):
                try:
                    similar = calc_similar_by_path2(f1_full_path, f2_full_path)*100 
                    if similar > 90:
                        maxsimilar = similar if similar > maxsimilar else maxsimilar
                        print('%s and %s 相似度  %.3f%%'%(files[i],files[j], similar))
                except:
                    pass
    print(maxsimilar)
    
#    make_doc_data('test/TEST4/1.JPG', 'test/TEST4/2.JPG')



class Test(unittest.TestCase):


    def setUp(self):
        pass


    def tearDown(self):
        pass


    def testName(self):
        pass


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()